package com.zchao.util;

import java.security.Key;
import java.security.KeyPair;
import java.util.Date;
import java.util.Map;

import javax.crypto.SecretKey;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;

/**
 * JWT Token工具类
 * 
 * @description 先调用createSecretKey或createAsymmetricKeys方法创建密钥并保存起来，
 *              然后再调用createToken方法创建token，再利用保存的key调用parseToken方法解析或验证token
 * @author guozongchao
 *
 */
public class JwtTokenUtil {
	// Token 过期时间
	private static final int EXPIRATION_TIME = 3 * 60 * 1000;
	// 签发方
	private static final String ISSUER = "zchao";
	// 密钥(不同加密算法位数要求都不一样，位数不够会报异常，建议先调用createSecretKey方法产生随机强壮的密钥)
	private static final String SECRET_KEY = "MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCB7KZwyDaMC31jnKPUsh92tWOqO0gmQvs5zQyCglAugpQ==";

	/**
	 * 根据对称加密算法，随机产生一个对称密钥SecretKey
	 * 
	 * @see SignatureAlgorithm 查看更多加密算法
	 * @param algorithm
	 * @return SecretKey 通过Encoders.BASE64.encode(key.getEncoded())保存编码字符串
	 */
	public static SecretKey createSecretKey(SignatureAlgorithm algorithm) {
		return Keys.secretKeyFor(algorithm);
	}

	/**
	 * 获取非对称性密钥对KeyPair，签名token时需要用privateKey,解析或验证token时需要publicKey
	 * 
	 * @param algorithm
	 * @return KeyPair 通过Encoders.BASE64.encode(key.getEncoded())保存编码字符串
	 */
	public static KeyPair createAsymmetricKeys(SignatureAlgorithm algorithm) {
		return Keys.keyPairFor(algorithm);
	}

	/**
	 * 通过密钥签名token
	 * 
	 * @param claims
	 * @param key
	 * @return
	 */
	public static String createToken(Map<String, Object> claims, Key key) {
		String jws = Jwts.builder().setHeaderParam("typ", "JWT").setClaims(claims)
				.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)).setIssuer(ISSUER)
				.setIssuedAt(new Date()).signWith(key).compact();
		return jws;
	}

	/**
	 * 通过自定义密钥SECRET_KEY来签名token
	 * 
	 * @param claims
	 * @return
	 */
	public static String createToken(Map<String, Object> claims) {
		SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(SECRET_KEY));
		String jws = Jwts.builder().setHeaderParam("typ", "JWT").setClaims(claims)
				.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)).setIssuer(ISSUER)
				.setIssuedAt(new Date()).signWith(key).compact();
		return jws;
	}

	/**
	 * 通过密钥解析并验证token,非对称密钥通过publicKey解析或验证
	 * 
	 * @exception ExpiredJwtException
	 * @exception SignatureException
	 * @param token
	 * @param key
	 * @return
	 */
	public static Claims parseToken(String token, Key key) {
		return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();
	}

	/**
	 * 通过自定义密钥SECRET_KEY来解析验证token
	 * 
	 * @param token
	 * @return
	 */
	public static Claims parseToken(String token) {
		SecretKey key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(SECRET_KEY));
		return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();
	}

}
